package ru.niir.goodfil.ui;

import com.sun.rave.web.ui.appbase.AbstractSessionBean;
import org.apache.log4j.Logger;
import ru.niir.goodfil.db.Client;
import ru.niir.goodfil.db.GoodfilUtils;
import ru.niir.goodfil.db.Role;
import ru.niir.goodfil.db.User;

import javax.servlet.http.HttpSession;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

/**
 * Бин для хранения данных об авторизации клиента
 */
public class SecurityBean extends AbstractSessionBean {
    private static final String SESSION_BEAN_KEY = "SessionBean";

    private static Logger securityLogger = Logger.getLogger("Security");

    /**
     * Флаг обозначает, что вход в систему произведен
     */
    private boolean authorised = false;

    /**
     * Идентификатор клиента, если залогинен клиент
     */
    private long clientId = -1;

    /**
     * Идентификатор залогиненного пользователя (клиента или сотрудника)
     */
    private long userId = -1;

    /**
     * Идентификаторы менеджеров, подчиненных данному
     */
    private final Set<Long> subusers = new HashSet<Long>();

    /**
     * Дата входа
     */
    private Timestamp loginDate;

    /**
     * Возвращает true, если вход в систему был произведен
     */
    public boolean getIsAuthorized() {
      //  if (!isSecurityEnabled()) return true;
        return authorised;
    }

    /**
     * Возвращает true, если в системе залогинен клиент
     *
     * @return true, если в системе залогинен клиент
     */
    public boolean getIsClient() {
        if (!isSecurityEnabled()) return true;
        return clientId != -1 && userId != -1;
    }

    /**
     * Возвращает true, если в системе залогинен сотрудник
     *
     * @return true, если в системе залогинен сотрудник
     */
    public boolean getIsEmployee() {
        if (!isSecurityEnabled()) return true;
        return clientId == -1 && userId != -1;
    }

    /**
     * Возвращает идентификатор залогиненного клиента
     *
     * @return идентификатор залогиненного клиента
     */
    public long getClientId() {
        if (!isSecurityEnabled()) return -1;
        return clientId;
    }

    /**
     * Возвращает идентификатор залогиненного пользователя
     *
     * @return идентификатор залогиненного пользователя
     */
    public long getUserId() {
        if (!isSecurityEnabled()) return -1;
        return userId;
    }

    /**
     * Зарегистрировать вход в систему клиента
     *
     * @param clientId идентификатор клиента
     * @param userId   идентификатор пользователя, связанного с этим клиентом
     */
    public void loginClient(long clientId, long userId) {
        assert clientId != -1;
        assert userId != -1;

        this.user = null;
        this.client = null;

        this.clientId = clientId;
        this.userId = userId;

        this.loginDate = GoodfilUtils.getCurrentTimestamp();
        this.authorised = true;

        securityLogger.info("Client login proceed: clientId=" + clientId + ", userId=" + userId);
    }

    /**
     * Зарегистрировать вход в систему сотрудника
     *
     * @param userId идентификатор пользователя
     */
    public void loginEmployee(long userId) {
        assert userId != -1;

        this.user = null;
        this.client = null;

        this.userId = userId;

        this.loginDate = GoodfilUtils.getCurrentTimestamp();
        this.authorised = true;

        //  Блокировка фильтров
        //  TODO: Возможно, в блокировке фильтров не учитывается подчинение менеджеров
        if (!getIsRoleAdministrator()) {
            securityLogger.debug("Locking filters");
            getSessionBean().getClientsFilter().lockManagerId(userId);
            getSessionBean().getOrdersFilter().lockManagerId(userId);

            Calendar calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, 0);
            calendar.set(Calendar.MINUTE, 0);
            calendar.set(Calendar.SECOND, 0);
            calendar.set(Calendar.MILLISECOND, 0);
            getSessionBean().getOrdersFilter().setBegDate(calendar);

            calendar = Calendar.getInstance();
            calendar.set(Calendar.HOUR_OF_DAY, 23);
            calendar.set(Calendar.MINUTE, 59);
            calendar.set(Calendar.SECOND, 59);
            calendar.set(Calendar.MILLISECOND, 0);
            getSessionBean().getOrdersFilter().setEndDate(calendar);
        }

        if (getIsRoleManager()) {
            //  Получаем замещаемых менеджеров
            subusers.clear();
            subusers.addAll(getSessionBean().getGoodfil().getReplacedManagersByAssistantId(userId));
        }

        User currentUser = getCurrentUser();
        String username = String.valueOf(currentUser.getId()) + ": " +
                currentUser.getFio() + " [" +
                currentUser.getLogin() + "]";

        getSessionBean().getGoodfil().setUsername(username);
        getSessionBean().getGoodfil().setLoginDate(new Date(loginDate.getTime()));

        securityLogger.info("User login proceed: userId=" + userId);
    }

    /**
     * Выход из системы
     */
    public void logout() {
        if (getIsClient()) securityLogger.info("Client logout proceed: clientId=" + clientId + ", userId=" + userId);
        else securityLogger.info("User logout proceed: userId=" + userId);

        authorised = false;
        clientId = -1;
        userId = -1;
        loginDate = null;
        subusers.clear();

        user = null;
        client = null;

        //  Снятие блокировки фильтров
        securityLogger.debug("Unlocking filters");
        getSessionBean().getClientsFilter().unlockManagerId();
        getSessionBean().getOrdersFilter().unlockManagerId();

        //  Реинициализация сессии
        HttpSession session = (HttpSession) getFacesContext().getExternalContext().getSession(true);
        session.invalidate();
    }

    /**
     * Возвращает дату входа в систему
     *
     * @return дату входа в систему
     */
    public Timestamp getLoginDate() {
        if (!isSecurityEnabled()) return new Timestamp(Calendar.getInstance().getTime().getTime());
        return loginDate;
    }

    /**
     * Возвращает дату входа в систему в виде строки
     *
     * @return дату входа в систему в виде строки
     */
    public String getLoginDateAsString() {
        if (!isSecurityEnabled()) return "Авторизация отключена";
        SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm");
        return sdf.format(loginDate);
    }

    /**
     * Получить сессионный бин
     */
    protected SessionBean getSessionBean() {
        return (SessionBean) getBean(SESSION_BEAN_KEY);
    }

    private User user;
    private Client client;

    /**
     * Получить данные о текущем (залогиненном) пользователе системы
     */
    public User getCurrentUser() {
        if (user == null) {
            user = getSessionBean().getGoodfil().getUserById(userId);
        }
        return user;
    }

    /**
     * Получить данные о текущем (залогиненном) клиенте системы
     */
    public Client getCurrentClient() {
        if (client == null) {
            client = getSessionBean().getGoodfil().getClientById(clientId);
        }
        return client;
    }

    public long getRoleId() {
        return getCurrentUser().getUserRoleId();
    }

    public boolean getIsRoleAdministrator() {
        if (!isSecurityEnabled()) return true;
        if (!authorised) return false;
        return getCurrentUser().getUserRoleId() == Role.ADMIN;
    }

    public boolean getIsRoleManager() {
        if (!isSecurityEnabled()) return false;
        if (!authorised) return false;
        return getCurrentUser().getUserRoleId() == Role.MANAGER;
    }

    public boolean getIsRoleStoreman() {
        if (!isSecurityEnabled()) return false;
        if (!authorised) return false;
        return getCurrentUser().getUserRoleId() == Role.STOREMAN;
    }

    public boolean getIsRoleClient() {
        if (!authorised) return false;
        return getCurrentUser().getUserRoleId() == Role.CLIENT;
    }

    public boolean getIsRoleKassa(){
        if (!isSecurityEnabled()) return false;
        if(!authorised) return false;
        return getCurrentUser().getUserRoleId() == Role.KASSA;
    }
    /**
     * Функция возвращает true, если текущий пользователь имеет доступ к клиентам и заказам указанного менеджера.
     *
     * @param managerId идентификатор менеджера
     * @return true, если текущий пользователь имеет доступ к клиентам и заказам указанного менеджера
     */
    public boolean isManagerCorrect(long managerId) {
        if (!isSecurityEnabled()) return true;
        if (!authorised) return false;

        //  UNSAFE: На самом деле здесь нужно проверять и всех дочерних менеджеров тоже, но я пока не знаю как
        return getIsRoleAdministrator() || userId == managerId || subusers.contains(managerId);
    }

    public boolean getCanEditeStorageCount(){
        return getIsRoleAdministrator() || getIsRoleKassa() || getIsRoleStoreman();
    }

    private boolean isSecurityEnabled() {
        return getSessionBean().getGoodfil().getIntOrCreateIfNotExists(".security.enabled", 0, "Авторизация включена") != 0;
    }
}
